//
//  LYNetworkManager.swift
//  LYOnlineBanking
//
//  Created by 李永彬 on 2025/7/19.
//

import Foundation
import Alamofire

enum NetworkError: Error {
    // 客户端错误
    case invalidURL              // URL 构造失败
    case invalidRequest          // 请求参数错误
    case encodingFailed          // 参数编码失败（如 JSON 编码）
    
    // 服务器错误
    case serverError(statusCode: Int, data: Data?) // HTTP 状态码错误（如 404、500）
    
    // 网络层错误
    case alamofireError(Error)   // Alamofire 底层错误（如网络不可用）
    case rawError(data: Data, error: Error) // 原始错误 + 服务器返回的 Data（可能包含错误详情）
    
    // 数据解析错误
    case decodingFailed(Error)   // JSON 解析失败
    case emptyData               // 服务器返回空数据
    
    case customError(Error)         // 自定义错误类型
    
    // 其他自定义错误
    case unauthorized            // 401 未授权
    case timeout                 // 请求超时
    case unknown                 // 未知错误
}

enum APIDomain: String {
    case api = "http://8.215.86.57:7803/fod"
    case h5 = "http://8.215.86.57:7803"
    case auth = "https://auth.example.com"
    
    func fullPath(_ path: String) -> String {
        return self.rawValue + path
    }
}

// 定义ContentType枚举
enum ContentType {
    case formUrlEncoded  // application/x-www-form-urlencoded (默认)
    case json           // application/json
    case multipartForm  // multipart/form-data
    case custom(String) // 自定义类型
    
    var headerValue: String {
        switch self {
        case .formUrlEncoded: return "application/x-www-form-urlencoded"
        case .json: return "application/json"
        case .multipartForm: return "multipart/form-data"
        case .custom(let value): return value
        }
    }
    
    var encoding: ParameterEncoding {
        switch self {
        case .formUrlEncoded: return URLEncoding.default
        case .json: return JSONEncoding.default
        case .multipartForm: return URLEncoding.default // 实际multipart上传使用特殊处理
        case .custom: return URLEncoding.default
        }
    }
}

class NetworkManager {
    static let shared = NetworkManager()
    
    private init() {}
    
    // 公共参数
    var commonParameters: [String: Any] {
        let params: [String: Any] = [
            "torquesque": "ios", // 终端版本
            "uxorfoodaire": "1.0.0", // App版本
            "vehivity": UIDevice.current.modelName, // 设备名称
            "dogmatkidator": idfv, // IDFV
            "gravcheckally": UIDevice.current.systemVersion, // 设备OS版本
            "nugatitor": "tunai-pasti", // 市场
            "finallyator": LYUserDefaults.shared.getString(forKey: userSessionIdKey) ?? "",
            "weise": idfv, // IDFV
            "diploon": LYUserDefaults.shared.getString(forKey: countryIdKey) ?? "" // 当前语言
        ]
        
        return params
    }
    
    private var shortVersion: String {
        return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
    }
    
    // 公共头部
    private var commonHeaders: HTTPHeaders = [
        "Accept": "application/json"
    ]
    
    private let session: Session = {
        let configuration = URLSessionConfiguration.af.default
        configuration.timeoutIntervalForRequest = 30
        configuration.timeoutIntervalForResource = 30
        return Session(configuration: configuration)
    }()
    
    // MARK: - 配置方法
    func setCommonHeaders(_ headers: HTTPHeaders) {
        self.commonHeaders = headers
    }
    
    func addCommonHeaders(_ headers: HTTPHeaders) {
        headers.forEach { self.commonHeaders.add($0) }
    }
    
    // MARK: - 通用请求方法
    
    func requestData(
        domain: APIDomain,
        path: String,
        method: HTTPMethod = .get,
        parameters: Parameters? = nil,
        contentType: ContentType = .formUrlEncoded,
        headers: HTTPHeaders? = nil,
        showLoginViewController: Bool = true,
        completion: @escaping (Result<Data, Error>) -> Void
    ) {
        let baseURL = domain.fullPath(path)
        let queryString = commonParameters.toURLQueryString()
        let urlString = "\(baseURL)?\(queryString)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
     
        guard let urlString = urlString,
              let url = URL(string: urlString) else {
            completion(.failure(NSError(domain: "NetworkError", code: -1)))
            return
        }
     
        var finalHeaders = commonHeaders
        finalHeaders.add(name: "Content-Type", value: contentType.headerValue)
        if let headers = headers {
            headers.forEach { finalHeaders.add($0) }
        }
        
        print("urlString: \(urlString)")
        print("parameters: \(String(describing: parameters))")
        
        applyDomainSpecificConfig(domain: domain, headers: &finalHeaders)
        
        session.request(
            url,
            method: method,
            parameters: parameters,
            encoding: contentType.encoding,
            headers: finalHeaders
        ).validate().responseData { response in
            switch response.result {
            case .success(let data):
                self.handleData(data: data, completion: completion)
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }
    
    func handleData(data: Data,
                    completion: @escaping (Result<Data, Error>) -> Void) {
        
        do {
            if let jsonString = String(data: data, encoding: .utf8) {
                print("response: \(jsonString)")
            }

            let decoder = JSONDecoder()
            let response = try decoder.decode(Response<Temp>.self, from: data)
            if response.dipsiaization == -2 {
                completion(.failure(NSError(domain: "NetworkError",
                                            code: -2,
                                            userInfo: [NSLocalizedDescriptionKey: response.motherling])))
                NotificationCenter.default.post(name: .NotLoginInNotificationKey, object: nil)

            } else if response.dipsiaization == 0 {
                completion(.success(data))
            } else {
                completion(.failure(NSError(domain: "NetworkError",
                                            code: response.dipsiaization,
                                            userInfo: [NSLocalizedDescriptionKey: response.motherling])))
            }
        } catch {
            print(error.localizedDescription)
        }
    }
    
    struct Temp: Codable {}
    
    // MARK: - Multipart表单上传
    
    func uploadMultipart(
        domain: APIDomain,
        path: String,
        parameters: [String: String]? = nil,
        fileData: Data,
        fileName: String,
        mimeType: String,
        headers: HTTPHeaders? = nil,
        completion: @escaping (Result<Data, Error>) -> Void
    ) {
        let baseURL = domain.fullPath(path)
        let queryString = commonParameters.toURLQueryString()
        let urlString = "\(baseURL)?\(queryString)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
     
        guard let urlString = urlString else {
            completion(.failure(NSError(domain: "NetworkError", code: -1)))
            return
        }
        
        guard let url = URL(string: urlString) else {
            completion(.failure(NSError(domain: "NetworkError", code: -1)))
            return
        }
        
        // 合并头部
        var finalHeaders = commonHeaders
        finalHeaders.add(name: "Content-Type", value: ContentType.multipartForm.headerValue)
        if let headers = headers {
            headers.forEach { finalHeaders.add($0) }
        }
        
        // 域名特定配置
        applyDomainSpecificConfig(domain: domain, headers: &finalHeaders)
        
        session.upload(
            multipartFormData: { multipartFormData in
                // 添加文件数据
                multipartFormData.append(
                    fileData,
                    withName: "rememberile",
                    fileName: fileName,
                    mimeType: mimeType
                )
                
                // 添加普通参数
                parameters?.forEach { key, value in
                    multipartFormData.append(value.data(using: .utf8)!, withName: key)
                }
                
                // 添加公共参数
                self.commonParameters.forEach { key, value in
                    if let stringValue = value as? String {
                        multipartFormData.append(stringValue.data(using: .utf8)!, withName: key)
                    } else if let numberValue = value as? NSNumber {
                        multipartFormData.append(numberValue.stringValue.data(using: .utf8)!, withName: key)
                    }
                }
            },
            to: url,
            method: .post,
            headers: finalHeaders
        ).validate().responseData {  response in
            switch response.result {
            case .success(let data):
                self.handleData(data: data, completion: completion)
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }
    
    // MARK: - 私有方法
    
    private func applyDomainSpecificConfig(domain: APIDomain, headers: inout HTTPHeaders) {
//        switch domain {
//        case .auth:
//            headers.add(name: "Authorization", value: "Bearer \(getAuthToken())")
//        case .payment:
//            headers.add(name: "X-Payment-Version", value: "2.0")
//        default:
//            break
//        }
    }
    
    private func handleResponse<T: Decodable>(
        _ response: AFDataResponse<T>,
        completion: @escaping (Result<T, NetworkError>) -> Void
    ) {
        switch response.result {
        case .success(let value):
            completion(.success(value))
        case .failure(let error):
            if let data = response.data {
                completion(.failure(.rawError(data: data, error: error)))
            } else {
                completion(.failure(.alamofireError(error)))
            }
        }
    }
    
    private func getAuthToken() -> String {
        return UserDefaults.standard.string(forKey: "authToken") ?? ""
    }
}

// 服务器错误模型
struct ServerError: Decodable {
    let message: String
    let code: Int
}

// 设备型号扩展
extension UIDevice {
    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        
        // 映射常见设备名称
        let deviceMapping = [
            "iPhone1,1": "iPhone",
            "iPhone1,2": "iPhone 3G",
            "iPhone2,1": "iPhone 3GS",
            "iPhone3,1": "iPhone 4",
            "iPhone3,2": "iPhone 4",
            "iPhone3,3": "iPhone 4",
            "iPhone4,1": "iPhone 4S",
            "iPhone5,1": "iPhone 5",
            "iPhone5,2": "iPhone 5",
            "iPhone5,3": "iPhone 5C",
            "iPhone5,4": "iPhone 5C",
            "iPhone6,1": "iPhone 5S",
            "iPhone6,2": "iPhone 5S",
            "iPhone7,1": "iPhone 6 Plus",
            "iPhone7,2": "iPhone 6",
            "iPhone8,1": "iPhone 6S",
            "iPhone8,2": "iPhone 6S Plus",
            "iPhone8,4": "iPhone SE (1st)",
            "iPhone9,1": "iPhone 7",
            "iPhone9,2": "iPhone 7 Plus",
            "iPhone9,3": "iPhone 7",
            "iPhone9,4": "iPhone 7 Plus",
            "iPhone10,1": "iPhone 8",
            "iPhone10,2": "iPhone 8 Plus",
            "iPhone10,4": "iPhone 8",
            "iPhone10,5": "iPhone 8 Plus",
            "iPhone10,3": "iPhone X",
            "iPhone10,6": "iPhone X",
            "iPhone11,2": "iPhone XS",
            "iPhone11,4": "iPhone XS Max",
            "iPhone11,6": "iPhone XS Max",
            "iPhone11,8": "iPhone XR",
            "iPhone12,1": "iPhone 11",
            "iPhone12,3": "iPhone 11 Pro",
            "iPhone12,5": "iPhone 11 Pro Max",
            "iPhone13,1": "iPhone 12 mini",
            "iPhone13,2": "iPhone 12",
            "iPhone13,3": "iPhone 12 Pro",
            "iPhone13,4": "iPhone 12 Pro Max",
            "iPhone14,4": "iPhone 13 mini",
            "iPhone14,5": "iPhone 13",
            "iPhone14,2": "iPhone 13 Pro",
            "iPhone14,3": "iPhone 13 Pro Max",
            "iPhone14,6": "iPhone SE (3rd)",
            "iPhone14,7": "iPhone 14",
            "iPhone14,8": "iPhone 14 Plus",
            "iPhone15,2": "iPhone 14 Pro",
            "iPhone15,3": "iPhone 14 Pro Max",
            "iPhone15,4": "iPhone 15",
            "iPhone15,5": "iPhone 15 Plus",
            "iPhone16,1": "iPhone 15 Pro",
            "iPhone16,2": "iPhone 15 Pro Max"
        ]
        
        return deviceMapping[identifier] ?? identifier
    }
}
